﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using CalculatePrimeSample.EventHandler;
using CalculatePrimeSample.EventArgs;

namespace CalculatePrimeSample
{
    public partial class FormCalculatePrime : Form
    {
        private Guid mCalculateTaskId = Guid.Empty;

        private SynchronizationContext _syncContext = null;

        public FormCalculatePrime()
        {
            InitializeComponent();
            
            CheckForIllegalCrossThreadCalls = true;
            btnCancel.Enabled = false;
        }

        private void btnStart_Click(object sender, System.EventArgs e)
        {
            Console.WriteLine("main thread id:{0}",Thread.CurrentThread.ManagedThreadId);

            int numberToTest = 1;
            if (int.TryParse(txtbCount.Text, out numberToTest))
            {
                btnStart.Enabled = false;
                btnCancel.Enabled = true;

                rtxtbPrimes.Clear();

                mCalculateTaskId = Guid.NewGuid();
                mPrimeNumberCalculator.CalculatePrimeAsync(numberToTest, mCalculateTaskId);
            }
        }

        private void btnCancel_Click(object sender, System.EventArgs e)
        {
            if (mPrimeNumberCalculator != null)
            {
                mPrimeNumberCalculator.CancelAsync(mCalculateTaskId);
            }

            btnStart.Enabled = true;
            btnCancel.Enabled = false;
        }

        private void mPrimeNumberCalculator_OnCalculateProgressChanged(CalculatePrimeProgressChangedEventArgs e)
        {
            //when use AsyncOperation to post a SendOrPostCallback to UI thread which is the main thread in this program, 
            //the callback's thread does not run in asynchronous thread. But while triggering the defined progress changed event, the managed thread id is thread built for asynchronous operation
            //it is diffcault to understand the reason. it seems that SendOrPostCallback just an reference of the function,event though the SendOrPostCallback you create everytime
            Console.WriteLine("call back thread id:{0}",Thread.CurrentThread.ManagedThreadId);

            if (rtxtbPrimes.InvokeRequired)
            {
                rtxtbPrimes.Invoke(new MethodInvoker(delegate
                {
                    rtxtbPrimes.AppendText(e.LatestPrimeNumber + ",");
                    tpbCalculateProgress.Value = e.ProgressPercentage;
                }));
            }
            else
            {
                rtxtbPrimes.AppendText(e.LatestPrimeNumber + ",");
                tpbCalculateProgress.Value = e.ProgressPercentage;
            }
        }

        private void mPrimeNumberCalculator_OnCalculatePrimeCompleted(object sender, CalculatePrimeCompletedEventArgs e)
        {
            btnStart.Enabled = true;
            btnCancel.Enabled = false;
            tpbCalculateProgress.Value = 100;
            MessageBox.Show("Calculate Prime Completed!", "Calculator", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        private void OnCalculateProgressCallback(int prime,int percentage)
        {
            Console.Write(Thread.CurrentThread.ManagedThreadId);

            //why the richtextbox control's property of "InvokeRequired" is always false?
            if (rtxtbPrimes.InvokeRequired)
            {
                rtxtbPrimes.Invoke(new MethodInvoker(delegate
                {
                    rtxtbPrimes.AppendText(prime.ToString() + ",");
                    tpbCalculateProgress.Value = percentage;
                }));
            }
            else
            {
                rtxtbPrimes.AppendText(prime.ToString() + ",");
                tpbCalculateProgress.Value = percentage;
            }
        }
    }
}
